home *** CD-ROM | disk | FTP | other *** search
/ AGA Toolkit '97 / The AGA Toolkit '97.iso / programming / debug / calls / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-07  |  7.9 KB  |  325 lines

  1. /*
  2.  * main.c -- calls mainline, trace calling sequences of C programs
  3.  */
  4.  
  5. #ifdef pdp11
  6. #include <sys/types.h>
  7. #endif
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <strings.h>
  12. #ifdef __amigados__
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #endif
  16. #include "scan.h"
  17. #include "getopt.h"
  18. #include "main.h"
  19.  
  20. /* globals */
  21. char
  22.     sbCmd[] = "cmd line";   /* kludge to notify user of error       */
  23. int
  24.     Allp = 0,        /* flag to show *all* function calls    */
  25.     Tersep = 0,        /* only requested trees         */
  26.     Externp = 0,        /* include externs in index        */
  27.     Indexp = 0,        /* output functions index        */
  28.     Verbosep = 1;        /* index functions not output        */
  29.  
  30. /* locals */
  31. static int
  32.     linect = 0,        /* line number                */
  33.     activep = 0,        /* current function being output    */
  34.     iWidth = PAPERWIDTH;    /* default paper width            */
  35. static char
  36.     *pchProg,        /* argv[0]                */
  37.     cppcommand[1024] =    /* cpp command string            */
  38. #ifndef __amigados__
  39.         "/lib/cpp -P ";
  40. #else
  41.         "/bin/gcc -E -P ";
  42. #endif
  43. static HASH
  44.     *activelist[MAXDEPTH];    /* list of current output names     */
  45.  
  46.  
  47. char *
  48. syserrlist()    /*  the routine returns a string for a system error     */
  49. {
  50.     extern char *sys_errlist[];
  51.     extern int sys_nerr;
  52.     extern int errno;
  53.     register char *pchErr =
  54.         errno == 0 ? "errno = 0" :
  55.         errno < sys_nerr ? sys_errlist[errno] : "errno out of range";
  56.  
  57.     errno = 0;
  58.     return pchErr;
  59. }
  60.  
  61. void
  62. process(filename, outname)      /* invoke cpp on file, call level1      */
  63. register char *filename, *outname;
  64. {
  65.     extern FILE *popen();
  66.     register char *sbNull;
  67.     register int ret;
  68.  
  69.     if (access(filename, 04) != 0) {
  70.         (void) fprintf(stderr, "%s: cannot open file '%s' (%s).\n", pchProg, filename, syserrlist());
  71.         return;
  72.     }
  73.     sbNull = cppcommand + strlen(cppcommand);
  74.     strcpy(sbNull, filename);
  75.     if (NULL == (input = popen(cppcommand, "r"))) {
  76.         (void) fprintf(stderr, "%s: fork of CPP command '%s' failed on file '%s' (%s).\n", pchProg, cppcommand, filename, syserrlist());
  77.     } else {
  78.         level1(outname);
  79.         if (0 != (ret = pclose(input)))
  80.             (void) fprintf(stderr, "%s: CPP command '%s' failed on file '%s' with return code %d.\n", pchProg, cppcommand, filename, ret);
  81.     }
  82.     *sbNull = '\0';
  83.     return;
  84. }
  85.  
  86. void
  87. dostdin()       /* copy stdin to temp file, call process on file        */
  88. {
  89.     extern char *mktemp();
  90.     register int cc;
  91.     register char *filename = mktemp("/tmp/callsXXXXXX");
  92.     register FILE *ofileptr = fopen(filename, "w");
  93.     register char *sbNull;
  94.  
  95.     if (NULL == ofileptr) {
  96.         (void) fprintf(stderr, "%s: cannot open tempfile '%s' for writing (%s).\n", pchProg, filename, syserrlist());
  97.     } else {
  98.         while (EOF != (cc = getchar()))
  99.             putc(cc, ofileptr);
  100.         fclose(ofileptr);
  101.         sbNull = cppcommand + strlen(cppcommand);
  102.         strcpy(sbNull, "-I. ");
  103.         process(filename, "stdin");
  104.         *sbNull = '\000';
  105.         unlink(filename);
  106.     }
  107. }
  108.  
  109. int
  110. active(func)    /* check for recursive calls, prevents endless output   */
  111. register HASH *func;
  112. {
  113.     register int i;
  114.  
  115.     for (i = 0; i < activep-1; i++)
  116.         if (func == activelist[i])
  117.             return 1;
  118.     return 0;
  119. }
  120.  
  121. void
  122. output(pHTFunc, tabc)   /* output a (sub)tree in pretty form            */
  123. register HASH *pHTFunc;
  124. register int tabc;
  125. {
  126.     static char dashes[] = "\n----------";
  127.     register INST *pINTemp;
  128.     register int i;
  129.  
  130.     ++linect;
  131.     (void) printf("\n%5d\t", linect);
  132.     if (activep < MAXDEPTH) {
  133.         activelist[activep++] = pHTFunc;
  134.     } else {
  135.         (void) printf("   * nesting is too deep");
  136.         return;
  137.     }
  138.  
  139.     for (i = 0; i < tabc; i++ )
  140.         putchar('\t');
  141.     printf("%s", pHTFunc->pchname);
  142.  
  143.     if (active(pHTFunc)) {
  144.         (void) printf(" <<< recursive >>>");
  145.     } else if (pHTFunc->pchfile) {
  146.         pINTemp = pHTFunc->pINcalls;
  147.         if (pHTFunc->listp && tabc && 0 == pHTFunc->iline) {
  148.             (void) printf(" [%s] [see below]", pHTFunc->pchfile);
  149.         } else if (! pHTFunc->iline) {
  150.             (void) printf(pHTFunc->localp ? " [static in %s]" : " [%s]", pHTFunc->pchfile);
  151.             pHTFunc->iline = linect;
  152.             if ((++tabc) * TABWIDTH >= iWidth) {
  153.                 (void) printf(dashes);
  154.                 tabc = 0;
  155.             }
  156.             while (pINTemp) {
  157.                 output(pINTemp->pHTname, tabc);
  158.                 pINTemp = pINTemp->pINnext;
  159.             }
  160.             if (! tabc)
  161.                 (void) printf(dashes);
  162.         } else if (pINTemp || pHTFunc->localp) {
  163.             (void) printf(" [see line %d]", pHTFunc->iline);
  164.         }
  165.     }
  166.     activelist[activep--] = nilHASH;
  167. }
  168.  
  169. int
  170. main(argc, argv)        /* parse args, add files, call output           */
  171. int argc;
  172. char *argv[];
  173. {
  174.     extern int atoi();
  175.     static char sbOpts[] = "aehitvw:D:f:F:U:I:"; /* valid options   */
  176.     static char sbTemp[200];
  177.     static LIST *pCLRoot;
  178.     register HASH *pHTList;
  179.     register int cOption;
  180.     register LIST **ppCL;
  181.     register char *pchSplit;
  182.  
  183. #ifndef pdp11
  184.     setlinebuf(stdout);
  185. #endif
  186.     pchProg = argv[0];
  187.     ppCL = & pCLRoot;
  188.  
  189.     while (EOF != (cOption = getopt(argc, argv, sbOpts))) {
  190.         switch (cOption) {
  191.         case 'a':
  192.             Allp = 1;
  193.             break;
  194.         case 'e':
  195.             Externp = 1;
  196.             Indexp = 1;
  197.             break;
  198.         case 'F':
  199.             if (0 != (pchSplit = index(optarg, '/'))) {
  200.                 *pchSplit++ = '\000';
  201.             } else {
  202.         case 'f':
  203.                 pchSplit = sbCmd;
  204.             }
  205.             pHTList = search(optarg, 'F' == cOption, pchSplit);
  206.             pHTList->listp = 1;
  207.             pHTList->pchfile = pchSplit;
  208.             *ppCL = newCL();
  209.             (*ppCL)->pCLnext = pCLRoot;
  210.             (*ppCL)->pHTlist = pHTList;
  211.             ppCL = & (*ppCL)->pCLnext;
  212.             break;
  213.         case 't':
  214.             Tersep = 1;
  215.             break;
  216.         case 'v':
  217.             Verbosep = 0;
  218.             /*fallthrough*/
  219.         case 'i':
  220.             Indexp = 1;
  221.             break;
  222.         case 'w':
  223.             if (0 >= (iWidth = atoi(optarg)))
  224.                 iWidth = PAPERWIDTH;
  225.             break;
  226. #ifdef OLD_AND_BROKEN_SPRINTF
  227.         case 'D':
  228.             strcat(cppcommand, (const char *)
  229.                         sprintf(sbTemp, "-D%s ", optarg));
  230.             break;
  231.         case 'I':
  232.             strcat(cppcommand, (const char *)
  233.                         sprintf(sbTemp, "-I%s ", optarg));
  234.             break;
  235.         case 'U':
  236.             strcat(cppcommand, (const char *)
  237.                         sprintf(sbTemp, "-U%s ", optarg));
  238.             break;
  239. #else
  240.         case 'D':
  241.             sprintf(sbTemp, "-D%s ", optarg);
  242.             strcat(cppcommand,sbTemp);
  243.             break;
  244.         case 'I':
  245.             sprintf(sbTemp, "-I%s ", optarg);
  246.             strcat(cppcommand,sbTemp);
  247.             break;
  248.         case 'U':
  249.             sprintf(sbTemp, "-U%s ", optarg);
  250.             strcat(cppcommand,sbTemp);
  251.             break;
  252. #endif /* sprintf */
  253.         case '?':
  254.         case 'h':
  255.             (void) fprintf(stderr, "usage: %s [-aehitv] [-f function] [-F function[/file.c]] [-w width]\n\
  256.     [-D define] [-U undefine] [-I include-dir] [filename|-]*\n\
  257. \ta\tprint all calls in every function body\n\
  258. \te\tindex external functions too\n\
  259. \tf,F\tstart calling trace at given function\n\
  260. \th\tprint this message\n\
  261. \ti\tprint an index of defined functions\n\
  262. \tv\tlist only called functions in index output\n\
  263. \tt\tterse, list only trees that are requested\n\
  264. \tw\tset ouptut width\n\
  265. \tD,U,I\tas in cpp\n", pchProg);
  266.             exit('h' != cOption);
  267.         }
  268.     }
  269.     *ppCL = nilCL;
  270.  
  271.     while (EOF != getarg(argc, argv)) {
  272.         if ('-' == optarg[0] && '\000' == optarg[1])
  273.             dostdin();
  274.         else
  275.             process(optarg, optarg);
  276.     }
  277.  
  278.     while (pCLRoot) {               /* print requested trees        */
  279.         output(pCLRoot->pHTlist, 0);
  280.         putchar('\n');
  281.         pCLRoot = pCLRoot->pCLnext;
  282.     }
  283.  
  284.     if (!Tersep) {                  /* print other trees            */
  285.         for (cOption = 0; cOption < 2; ++cOption) {
  286.             for (pHTList = pHTRoot[cOption]; pHTList; pHTList = pHTList->pHTnext) {
  287.                 if (!pHTList->calledp && NULL != pHTList->pchfile && 0 == pHTList->iline) {
  288.                     output(pHTList, 0);
  289.                     putchar('\n');
  290.                 }
  291.             }
  292.         }
  293.     }
  294.  
  295.     if (Indexp) {                   /* print index                  */
  296.         printf("\fIndex:\n");
  297.         while (nilHASH != pHTRoot[0] || nilHASH != pHTRoot[1]) {
  298.  
  299.             if (nilHASH == pHTRoot[0] || (nilHASH != pHTRoot[1] && strcmp(pHTRoot[0]->pchname, pHTRoot[1]->pchname) >= 0)) {
  300.                 pHTList = pHTRoot[1];
  301.                 pHTRoot[1] = pHTRoot[1]->pHTnext;
  302.             } else {
  303.                 pHTList = pHTRoot[0];
  304.                 pHTRoot[0] = pHTRoot[0]->pHTnext;
  305.             }
  306.             if (!Externp && NULL == pHTList->pchfile)
  307.                 continue;
  308.             if (!Verbosep && 0 == pHTList->iline)
  309.                 continue;
  310.             putchar('\t');
  311.             fputs(pHTList->pchname, stdout);
  312.             if (pHTList->localp) {
  313.                 printf(" [static in %s]", pHTList->pchfile);
  314.             } else if (((char *) 0) != pHTList->pchfile) {
  315.                 printf(" [%s]", pHTList->pchfile);
  316.             }
  317.             if (0 != pHTList->iline) {
  318.                 printf(" [see line %d]", pHTList->iline);
  319.             }
  320.             putchar('\n');
  321.         }
  322.     }
  323.     exit(0);
  324. }
  325.